#import "cn1socket_NativeSocketImpl.h"

@implementation cn1socket_NativeSocketImpl

-(NSString*)getException {
	NSString* s = exception;
	exception = NULL;
	return s;
}

-(NSString*)getExceptionMessage {
	return exceptionMessage;
}

-(void)connect:(NSString*)param param1:(int)param1 {
	CFReadStreamRef readStream;
	CFWriteStreamRef writeStream;

	CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)param, param1, &readStream, &writeStream);

	inputStream = (NSInputStream *)readStream;
	outputStream = (NSOutputStream *)writeStream;

	[inputStream retain];
	[outputStream retain];

	[inputStream open];
	[outputStream open];

	NSLog(@"-- connected");
}

-(void)close {
	NSLog(@"-- close");
	[inputStream close];
	[outputStream close];
}

-(int)available {
	if (![self isReady:inputStream]) {
		return -1;
	}
	uint8_t* buf;
	NSUInteger len;
	BOOL available = [inputStream getBuffer:&buf length:&len];
	return (int)len;
}

- (BOOL) isReady: (NSStream*)stream from:(NSString*)from {
	NSStreamStatus status = [stream streamStatus];
	NSError* error = [stream streamError];
	BOOL ready =
		exception == NULL &&
		error == NULL &&
		status != NSStreamStatusNotOpen &&
		status != NSStreamStatusClosed &&
		status != NSStreamStatusError;
	if (!ready) {
		NSLog([NSString stringWithFormat:@"-- notReady | %@", from]);
		exception = @"IOException";
		exceptionMessage = @"";
	}
	return ready;
}

-(int)read {
	if (![self isReady:inputStream from:@"read1"]) {
		return -1;
	}
	uint8_t buf[1];
	int bytesRead = [inputStream read:buf maxLength:1];
	if (bytesRead < 0) {
		exception = @"IOException";
		exceptionMessage = [[inputStream streamError] localizedDescription];
		return -1;
	} else if (bytesRead == 0) {
		return -1;
	} else {
		return buf[0];
	}
}

-(NSData*)read:(int)param {
	if (![self isReady:inputStream from:@"read2"]) {
		return NULL;
	}
	uint8_t buf[param];
	NSInteger bytesRead = [inputStream read:buf maxLength:param];
	if (bytesRead < 0) {
		exception = @"IOException";
		exceptionMessage = [[inputStream streamError] localizedDescription];
		return NULL;
	} else if (bytesRead == 0) {
		return NULL;
	}
	NSData* data = [NSData dataWithBytes:(const void *)buf length:bytesRead];
	return data;
}

-(void)flush {
	[self isReady:inputStream from:@"flush"];
}

-(void)write:(int)param {
	if (![self isReady:outputStream from:@"write"]) {
		return;
	}
	uint8_t buf[1];
	buf[0] = (uint8_t)param;
	NSInteger res = [outputStream write:buf maxLength:1];
	if (res <= 0){
		exception = @"IOException";
		exceptionMessage = [[outputStream streamError] localizedDescription];
	}
}

-(void)writeBuffer:(NSData*)buffer {
	if (![self isReady:outputStream from:@"writeBuffer"]) {
		return;
	}
	int bytesWritten = [outputStream write:(const uint8_t*)[buffer bytes] maxLength:[buffer length]];
	if (bytesWritten < 0) {
		exception = @"IOException";
		exceptionMessage = [[outputStream streamError] localizedDescription];
	} else if (bytesWritten != [buffer length]) {
		exception = @"IOException";
		exceptionMessage = [[outputStream streamError] localizedDescription];
	}
}

-(void)writeBuffer:(NSData*)buffer param1:(int)offset param2:(int)length {
	NSRange range = NSMakeRange(offset, length);
	uint8_t _buf[length];
	[buffer getBytes:_buf range:range];
	NSData* data = [NSData dataWithBytes:(const void *)_buf length:length];
	[self writeBuffer:data];
}

@end